From 299e4f806a57ffe3cab8f6497dd33f16c0b683e4 Mon Sep 17 00:00:00 2001 From: "mwilli2@equilibrium.research.intel-research.net" Date: Wed, 25 Feb 2004 15:34:58 +0000 Subject: [PATCH] bitkeeper revision 1.748.1.1 (403cc0a2uogkgkA4n8xi9XH9sph-GQ) Add support for setting the trace buffer size as a boot parameter, for returning the trace buffer size to user space and dynamically determining the number of CPUs to map in xentrace. --- docs/Xeno-HOWTO.txt | 4 + tools/xentrace/xentrace.c | 137 +++++++++++++++----------- xen/common/dom0_ops.c | 3 +- xen/common/kernel.c | 3 + xen/common/trace.c | 40 ++++++-- xen/include/hypervisor-ifs/dom0_ops.h | 7 +- xen/include/xeno/trace.h | 9 +- 7 files changed, 129 insertions(+), 74 deletions(-) diff --git a/docs/Xeno-HOWTO.txt b/docs/Xeno-HOWTO.txt index e30c74794d..9a74bbd749 100644 --- a/docs/Xeno-HOWTO.txt +++ b/docs/Xeno-HOWTO.txt @@ -225,6 +225,10 @@ The following is a list of command line arguments to pass to Xen: dom0_mem=xxx Set the maximum amount of memory for domain0. + tbuf_size=xxx Set the size of the per-cpu trace buffers, in pages + (default 1). Note that the trace buffers are only + enabled in debug builds. Most users can ignore + this feature completely. Boot into Domain 0 ============================== diff --git a/tools/xentrace/xentrace.c b/tools/xentrace/xentrace.c index 526c8152fc..8ac48331ff 100644 --- a/tools/xentrace/xentrace.c +++ b/tools/xentrace/xentrace.c @@ -27,11 +27,8 @@ extern FILE *stdout; -/***** Compile time configuration of defaults ********************************/ -#define NUM_CPUS 1 /* XXX this ought to be removed and replaced with something - * cleverer to dynamically query the machine - I'll use a - * dom0 op once I've implemented it! :-) */ +/***** Compile time configuration of defaults ********************************/ /* when we've got more records than this waiting, we log it to the output */ #define NEW_DATA_THRESH 1 @@ -39,11 +36,11 @@ extern FILE *stdout; /* sleep for this long (milliseconds) between checking the trace buffers */ #define POLL_SLEEP_MILLIS 100 + /***** The code **************************************************************/ typedef struct settings_st { char *outfile; - unsigned int num_cpus; struct timespec poll_sleep; unsigned long new_data_thresh; } settings_t; @@ -90,13 +87,14 @@ void print_rec(unsigned int cpu, struct t_rec *rec, FILE *out) /** - * get_tbuf_ptrs - get pointer to trace buffers + * get_tbufs - get pointer to and size of the trace buffers + * @phys_addr: location to store physical address if the trace buffers to + * @size: location to store the size of a trace buffer to * - * Does a dom0 op to fetch a "pointer" to the trace buffers. The pointer can't - * be dereferenced immediately, since it is a physical address of memory in Xen - * space - they are used in this program to mmap the right area from /dev/mem. + * Gets the physical address of the trace pointer area and the size of the + * per CPU buffers. */ -unsigned long get_tbuf_ptrs(void) +void get_tbufs(unsigned long *phys_addr, unsigned long *size) { int ret; dom0_op_t op; /* dom0 op we'll build */ @@ -114,22 +112,29 @@ unsigned long get_tbuf_ptrs(void) PERROR("Failure to get trace buffer pointer from Xen"); exit(EXIT_FAILURE); } - - return op.u.gettbufs.phys_addr; + + *phys_addr = op.u.gettbufs.phys_addr; + *size = op.u.gettbufs.size; } /** * map_tbufs - memory map Xen trace buffers into user space * @tbufs: physical address of the trace buffers + * @num: number of trace buffers to map + * @size: size of each trace buffer * - * Given the physical address of the Xen trace buffers, maps them into process - * address space by memory mapping /dev/mem. Returns a pointer to the location - * the buffers have been mapped to. + * Maps the Xen trace buffers them into process address space by memory mapping + * /dev/mem. Returns the location the buffers have been mapped to. */ -struct t_buf *map_tbufs(unsigned long tbufs_phys) +struct t_buf *map_tbufs(unsigned long tbufs_phys, unsigned int num, + unsigned long size) { - int dm_fd; /* file descriptor for /dev/mem */ + int dm_fd; /* file descriptor for /dev/mem */ struct t_buf *tbufs_mapped; + unsigned int page_size = getpagesize(); + unsigned int off_in_pg = (tbufs_phys % page_size); + + tbufs_phys -= off_in_pg; /* correct tbufs_phys if not page-aligned */ dm_fd = open("/dev/mem", O_RDONLY); if ( dm_fd < 0 ) @@ -137,8 +142,8 @@ struct t_buf *map_tbufs(unsigned long tbufs_phys) PERROR("Open /dev/mem when mapping trace buffers\n"); exit(EXIT_FAILURE); } - - tbufs_mapped = (struct t_buf *)mmap(NULL, opts.num_cpus * TB_SIZE, + + tbufs_mapped = (struct t_buf *)mmap(NULL, size * num + off_in_pg, PROT_READ, MAP_SHARED, dm_fd, (off_t)tbufs_phys); @@ -149,24 +154,28 @@ struct t_buf *map_tbufs(unsigned long tbufs_phys) PERROR("Failed to mmap trace buffers"); exit(EXIT_FAILURE); } - - return tbufs_mapped; + + /* add offset to get buffers in case original address wasn't pg aligned */ + return (struct t_buf *)((unsigned long)tbufs_mapped + off_in_pg); } /** * init_bufs_ptrs - initialises an array of pointers to the trace buffers * @bufs_mapped: the userspace address where the trace buffers are mapped + * @num: number of trace buffers + * @size: trace buffer size * * Initialises an array of pointers to individual trace buffers within the * mapped region containing all trace buffers. */ -struct t_buf **init_bufs_ptrs(void *bufs_mapped) +struct t_buf **init_bufs_ptrs(void *bufs_mapped, unsigned int num, + unsigned long size) { int i; struct t_buf **user_ptrs; - user_ptrs = (struct t_buf **)calloc(opts.num_cpus, sizeof(struct t_buf *)); + user_ptrs = (struct t_buf **)calloc(num, sizeof(struct t_buf *)); if ( user_ptrs == NULL ) { PERROR( "Failed to allocate memory for buffer pointers\n"); @@ -175,9 +184,9 @@ struct t_buf **init_bufs_ptrs(void *bufs_mapped) /* initialise pointers to the trace buffers - given the size of a trace * buffer and the value of bufs_maped, we can easily calculate these */ - for ( i = 0; idata - tbufs_phys + (unsigned long)tbufs_mapped); @@ -216,16 +227,17 @@ struct t_rec **init_rec_ptrs(unsigned long tbufs_phys, /** * init_tail_idxs - initialise an array of tail indexes - * @bufs: array of pointers to trace buffer metadata in struct t_buf's + * @bufs: array of pointers to trace buffer metadata + * @num: number of trace buffers * * The tail indexes indicate where we're read to so far in the data array of a * trace buffer. Each entry in this table corresponds to the tail index for a * particular trace buffer. */ -int *init_tail_idxs(struct t_buf **bufs) +int *init_tail_idxs(struct t_buf **bufs, unsigned int num) { int i; - int *tails = calloc(opts.num_cpus, sizeof(unsigned int)); + int *tails = calloc(num, sizeof(unsigned int)); if ( tails == NULL ) { @@ -233,12 +245,37 @@ int *init_tail_idxs(struct t_buf **bufs) exit(EXIT_FAILURE); } - for ( i = 0; ihead; return tails; } +/** + * get_num_cpus - get the number of logical CPUs + */ +unsigned int get_num_cpus() +{ + dom0_op_t op; + int xc_handle = xc_interface_open(); + int ret; + + op.cmd = DOM0_PHYSINFO; + op.interface_version = DOM0_INTERFACE_VERSION; + + ret = do_dom0_op(xc_handle, &op); + + if ( ret != 0 ) + { + PERROR("Failure to get logical CPU count from Xen"); + exit(EXIT_FAILURE); + } + + xc_interface_close(xc_handle); + + return op.u.physinfo.ht_per_core * op.u.physinfo.cores; +} + /** * monitor_tbufs - monitor the contents of tbufs and output to a file @@ -253,20 +290,25 @@ int monitor_tbufs(FILE *logfile) * where they are mapped into user space. */ int *tails; /* store tail indexes for the trace buffers */ unsigned long tbufs_phys; /* physical address of the tbufs */ - + unsigned int num; /* number of trace buffers / logical CPUS */ + unsigned long size; /* size of a single trace buffer */ + + /* get number of logical CPUs (and therefore number of trace buffers) */ + num = get_num_cpus(); + /* setup access to trace buffers */ - tbufs_phys = get_tbuf_ptrs(); - tbufs_mapped = map_tbufs(tbufs_phys); + get_tbufs(&tbufs_phys, &size); + tbufs_mapped = map_tbufs(tbufs_phys, num, size); /* build arrays of convenience ptrs */ - meta = init_bufs_ptrs (tbufs_mapped); - data = init_rec_ptrs (tbufs_phys, tbufs_mapped, meta); - tails = init_tail_idxs (meta); + meta = init_bufs_ptrs (tbufs_mapped, num, size); + data = init_rec_ptrs (tbufs_phys, tbufs_mapped, meta, num); + tails = init_tail_idxs (meta, num); /* now, scan buffers for events */ while ( !interrupted ) { - for ( i = 0; i < opts.num_cpus; i++ ) + for ( i = 0; ( i < num ) && !interrupted; i++ ) { signed long newdata = meta[i]->head - tails[i]; signed long prewrap = newdata; @@ -335,15 +377,6 @@ error_t cmd_parser(int key, char *arg, struct argp_state *state) argp_usage(state); } break; - - case 'n': /* set number of CPU trace buffers to map */ - { - char *inval; - setup->num_cpus = strtol(arg, &inval, 0); - if (inval == arg ) - argp_usage(state); - } - break; case ARGP_KEY_ARG: { @@ -376,11 +409,6 @@ const struct argp_option cmd_opts[] = "Set sleep time, p, in milliseconds between polling the trace buffer " "for new data (default " xstr(POLL_SLEEP_MILLIS) ")." }, - { .name = "num-cpus", .key = 'n', .arg="i", - .doc = - "Set number, i, of CPU trace buffers to map. This should not exceed " - "the number of CPUs in the system (default " xstr(NUM_CPUS) ")." }, - {0} }; @@ -399,7 +427,7 @@ const struct argp parser_def = }; -const char *argp_program_version = "xentrace v1.0"; +const char *argp_program_version = "xentrace v1.1"; const char *argp_program_bug_address = ""; @@ -411,7 +439,6 @@ int main(int argc, char **argv) const struct sigaction act = { .sa_handler = close_handler }; opts.outfile = 0; - opts.num_cpus = 1; opts.poll_sleep = millis_to_timespec(POLL_SLEEP_MILLIS); opts.new_data_thresh = NEW_DATA_THRESH; diff --git a/xen/common/dom0_ops.c b/xen/common/dom0_ops.c index ab81ca662c..6f829e135a 100644 --- a/xen/common/dom0_ops.c +++ b/xen/common/dom0_ops.c @@ -436,9 +436,8 @@ long do_dom0_op(dom0_op_t *u_dom0_op) #ifdef TRACE_BUFFER case DOM0_GETTBUFS: { - op->u.gettbufs.phys_addr = get_tb_ptr(); + ret = get_tb_info(&op->u.gettbufs); copy_to_user(u_dom0_op, op, sizeof(*op)); - ret = 0; } break; #endif diff --git a/xen/common/kernel.c b/xen/common/kernel.c index b113f2c812..3f1d0fd24c 100644 --- a/xen/common/kernel.c +++ b/xen/common/kernel.c @@ -77,6 +77,8 @@ int opt_ignorebiostables=0; int opt_watchdog=0; /* opt_pdb: Name of serial port for Xen pervasive debugger (and enable pdb) */ unsigned char opt_pdb[10] = "none"; +/* opt_tbuf_size: trace buffer size (in pages) */ +unsigned int opt_tbuf_size = 1; static struct { unsigned char *name; @@ -96,6 +98,7 @@ static struct { { "ignorebiostables", OPT_BOOL, &opt_ignorebiostables }, { "watchdog", OPT_BOOL, &opt_watchdog }, { "pdb", OPT_STR, &opt_pdb }, + { "tbuf_size", OPT_UINT, &opt_tbuf_size }, { NULL, 0, NULL } }; diff --git a/xen/common/trace.c b/xen/common/trace.c index 9a1d455631..aa2e7b949f 100644 --- a/xen/common/trace.c +++ b/xen/common/trace.c @@ -29,7 +29,9 @@ #include #include #include +#include #include +#include /* Pointers to the meta-data objects for all system trace buffers */ struct t_buf *t_bufs[NR_CPUS]; @@ -46,11 +48,20 @@ int tb_init_done = 0; */ void init_trace_bufs(void) { + extern int opt_tbuf_size; + int i; char *rawbuf; struct t_buf *buf; + + if ( opt_tbuf_size == 0 ) + { + printk("Xen trace buffers: disabled\n"); + return; + } - if ( (rawbuf = kmalloc(smp_num_cpus * TB_SIZE, GFP_KERNEL)) == NULL ) + if ( (rawbuf = kmalloc(smp_num_cpus * opt_tbuf_size * PAGE_SIZE, + GFP_KERNEL)) == NULL ) { printk("Xen trace buffers: memory allocation failed\n"); return; @@ -58,7 +69,7 @@ void init_trace_bufs(void) for ( i = 0; i < smp_num_cpus; i++ ) { - buf = t_bufs[i] = (struct t_buf *)&rawbuf[i*TB_SIZE]; + buf = t_bufs[i] = (struct t_buf *)&rawbuf[i*opt_tbuf_size*PAGE_SIZE]; /* For use in Xen. */ buf->vdata = (struct t_rec *)(buf+1); @@ -70,7 +81,8 @@ void init_trace_bufs(void) buf->head = 0; /* For use in both. */ - buf->size = (TB_SIZE - sizeof(struct t_buf)) / sizeof(struct t_rec); + buf->size = (opt_tbuf_size * PAGE_SIZE - sizeof(struct t_buf)) + / sizeof(struct t_rec); } printk("Xen trace buffers: initialised\n"); @@ -81,15 +93,29 @@ void init_trace_bufs(void) } /** - * get_tb_ptr - return physical address of the trace buffers. + * get_tb_info - get trace buffer details + * @st: a pointer to a dom0_gettbufs_t to be filled out * * Called by the %DOM0_GETTBUFS dom0 op to fetch the physical address of the * trace buffers. */ -unsigned long get_tb_ptr(void) +int get_tb_info(dom0_gettbufs_t *st) { - /* Return the physical address. */ - return __pa(t_bufs[0]); + if(tb_init_done) + { + extern unsigned int opt_tbuf_size; + + st->phys_addr = __pa(t_bufs[0]); + st->size = opt_tbuf_size * PAGE_SIZE; + + return 0; + } + else + { + st->phys_addr = 0; + st->size = 0; + return -ENODATA; + } } #endif /* TRACE_BUFFER */ diff --git a/xen/include/hypervisor-ifs/dom0_ops.h b/xen/include/hypervisor-ifs/dom0_ops.h index 5e0abe6295..5e47e64c0e 100644 --- a/xen/include/hypervisor-ifs/dom0_ops.h +++ b/xen/include/hypervisor-ifs/dom0_ops.h @@ -17,7 +17,7 @@ * This makes sure that old versions of dom0 tools will stop working in a * well-defined way (rather than crashing the machine, for instance). */ -#define DOM0_INTERFACE_VERSION 0xAAAA0007 +#define DOM0_INTERFACE_VERSION 0xAAAA0008 /* * The following is all CPU context. Note that the i387_ctxt block is filled @@ -213,8 +213,9 @@ typedef struct dom0_pincpudomain_st #define DOM0_GETTBUFS 21 typedef struct dom0_gettbufs_st { - /* OUT variable - location of the trace buffers */ - unsigned long phys_addr; + /* OUT variables */ + unsigned long phys_addr; /* location of the trace buffers */ + unsigned long size; /* size of each trace buffer, in bytes */ } dom0_gettbufs_t; /* diff --git a/xen/include/xeno/trace.h b/xen/include/xeno/trace.h index aa7ba5121c..9268145905 100644 --- a/xen/include/xeno/trace.h +++ b/xen/include/xeno/trace.h @@ -21,12 +21,6 @@ #ifndef __XENO_TRACE_H__ #define __XENO_TRACE_H__ -/* - * How much space is allowed for a single trace buffer, including data and - * metadata (and maybe some waste). - */ -#define TB_SIZE PAGE_SIZE - /* This structure represents a single trace buffer record. */ struct t_rec { u64 cycles; /* 64 bit cycle counter timestamp */ @@ -63,12 +57,13 @@ struct t_buf { #include #include #include +#include /* Used to initialise trace buffer functionality */ void init_trace_bufs(void); /* used to retrieve the physical address of the trace buffers */ -struct t_buf *get_tb_ptr(void); +int get_tb_info(dom0_gettbufs_t *st); /** * trace - Enters a trace tuple into the trace buffer for the current CPU. -- 2.30.2